package com.szeldon.declatest.declaration.reader;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;

import org.testng.Assert;
import org.testng.annotations.Test;

import com.szeldon.declatest.declaration.TestsSuiteDeclaration;
import com.szeldon.declatest.declaration.endpoints.EndpointDeclaration;
import com.szeldon.declatest.declaration.props.PropertyFileDeclaration;
import com.szeldon.declatest.declaration.reader.exceptions.TestSuiteFileException;
import com.szeldon.declatest.declaration.reader.settings.JMSSettingsReaderPlugin;
import com.szeldon.declatest.declaration.scenario.ScenarioDeclaration;
import com.szeldon.declatest.declaration.scenario.parts.CheckpointPartDeclaration;
import com.szeldon.declatest.declaration.scenario.parts.DoScenarioStepPartDeclaration;
import com.szeldon.declatest.declaration.scenario.parts.ElsePartDeclaration;
import com.szeldon.declatest.declaration.scenario.parts.EndPartDeclaration;
import com.szeldon.declatest.declaration.scenario.parts.ErrorPartDeclaration;
import com.szeldon.declatest.declaration.scenario.parts.IfPartDeclaration;
import com.szeldon.declatest.declaration.scenario.parts.NotComputedPartDeclaration;
import com.szeldon.declatest.declaration.scenario.parts.ReturnPartDeclaration;
import com.szeldon.declatest.declaration.scenario.parts.ScenarioPartDeclaration;
import com.szeldon.declatest.declaration.scenario.parts.ScenarioPartsTypeEnum;
import com.szeldon.declatest.declaration.settings.JmsSettingsPartDeclaration;
import com.szeldon.declatest.declaration.settings.SettingsDeclaration;
import com.szeldon.declatest.declaration.steps.ScenarioStepDeclaration;

/**
 * Tests for {@link XMLDeclarationReader}.
 * 
 * @author szeldon
 * 
 */
public class XMLDeclarationReaderTest {

    @Test()
    public void testProperXMLAllTags() throws FileNotFoundException, IOException, TestSuiteFileException {
        XMLDeclarationReader reader = new XMLDeclarationReader("tests-res/com/szeldon/declatest"
                + "/declaration/proper-declaration-01.xml");
        reader.addSettingsReaderPlugin(new JMSSettingsReaderPlugin());

        // test suite
        TestsSuiteDeclaration suite = reader.readTestsSuiteDeclaration();
        Assert.assertEquals(suite.getId(), "testsuite");
        Assert.assertEquals(suite.getDescription(), "Test TestSuite.");

        // property files
        List<PropertyFileDeclaration> fileList = suite.getPropertyFilesList();
        Assert.assertEquals(fileList.size(), 1);
        Assert.assertEquals(fileList.get(0).getLocation(),
                "tests-res/com/szeldon/declatest/declaration/proper-01.properties");

        // settings
        Collection<SettingsDeclaration> settings = suite.getSettings();
        Assert.assertEquals(settings.size(), 1);
        Iterator<SettingsDeclaration> settingsIterator = settings.iterator();
        SettingsDeclaration settings0 = settingsIterator.next();
        Assert.assertEquals(settings0.getClass(), JmsSettingsPartDeclaration.class);
        JmsSettingsPartDeclaration jmsSettings0 = (JmsSettingsPartDeclaration) settings0;
        Assert.assertEquals(settings0.getId(), "settings-id");
        Assert.assertEquals(settings0.getDescription(), "Some settings");
        Assert.assertEquals(jmsSettings0.getUsername(), "user");
        Assert.assertEquals(jmsSettings0.getPassword(), "password");
        Assert.assertEquals(jmsSettings0.getDestinationType(), "queue");
        Assert.assertEquals(jmsSettings0.getDestinationName(), "queue_name");
        Assert.assertEquals(jmsSettings0.getActivityType(), "send");

        // endpoints
        Collection<EndpointDeclaration> endpoints = suite.getEndpoints();
        Assert.assertEquals(endpoints.size(), 1);
        Iterator<EndpointDeclaration> endpointsIterator = endpoints.iterator();
        EndpointDeclaration endpoint0 = endpointsIterator.next();
        Assert.assertEquals(endpoint0.getId(), "endpoint-00");
        Assert.assertEquals(endpoint0.getDescription(), "endpoint-00-description");
        Assert.assertEquals(endpoint0.getUrl(), "http://example.com");
        Assert.assertEquals(endpoint0.getSettingsId(), "settings-id");

        // steps
        Collection<ScenarioStepDeclaration> steps = suite.getSteps();
        Assert.assertEquals(steps.size(), 2);
        Iterator<ScenarioStepDeclaration> stepsIterator = steps.iterator();
        ScenarioStepDeclaration step0 = stepsIterator.next();
        Assert.assertEquals(step0.getId(), "step-00");
        Assert.assertEquals(step0.getDescription(), "First step.");
        Assert.assertEquals(step0.getEndpointId(), "endpoint-00");
        Assert.assertEquals(step0.getRequestPath(), "request-00-path");
        ScenarioStepDeclaration step1 = stepsIterator.next();
        Assert.assertEquals(step1.getId(), "step-01");
        Assert.assertEquals(step1.getDescription(), "Second step.");
        Assert.assertEquals(step1.getEndpointId(), "endpoint-00");
        Assert.assertEquals(step1.getRequestPath(), "request-01-path");

        // scenarios
        List<ScenarioDeclaration> scenarios = suite.getScenarios();
        Assert.assertEquals(scenarios.size(), 1);
        ScenarioDeclaration scenario0 = scenarios.get(0);

        // // parts
        List<ScenarioPartDeclaration> parts = scenario0.getPartsList();
        Assert.assertEquals(parts.size(), 4);

        // // // if part
        ScenarioPartDeclaration part0 = parts.get(0);
        ScenarioPartsTypeEnum part0Type = part0.getPartType();
        Assert.assertEquals(part0Type, ScenarioPartsTypeEnum.IF_PART);
        IfPartDeclaration ifPart0 = (IfPartDeclaration) part0;
        Assert.assertEquals(ifPart0.getLeft(), "left-value");
        Assert.assertEquals(ifPart0.getOperator(), "some-operator");
        Assert.assertEquals(ifPart0.getRight(), "right-value");
        Assert.assertEquals(ifPart0.getDescription(), "some description");
        List<ScenarioPartDeclaration> part0Subparts = part0.getSubpartsList();
        Assert.assertEquals(part0Subparts.size(), 3);

        // // // // checkpoint
        ScenarioPartDeclaration part0Subpart0 = part0Subparts.get(0);
        ScenarioPartsTypeEnum part0Subpart0Type = part0Subpart0.getPartType();
        Assert.assertEquals(part0Subpart0Type, ScenarioPartsTypeEnum.CHECKPOINT_PART);
        CheckpointPartDeclaration checkPart0Subpart0 = (CheckpointPartDeclaration) part0Subpart0;
        Assert.assertEquals(checkPart0Subpart0.getId(), "checkpoint-00");
        Assert.assertEquals(checkPart0Subpart0.getDescription(), "some-checkpoint");

        // // // // scenario step exec
        ScenarioPartDeclaration part0Subpart1 = part0Subparts.get(1);
        ScenarioPartsTypeEnum part0Subpart1Type = part0Subpart1.getPartType();
        Assert.assertEquals(part0Subpart1Type, ScenarioPartsTypeEnum.DO_SCENARIO_STEP_PART);
        DoScenarioStepPartDeclaration execPart0Subpart1 = (DoScenarioStepPartDeclaration) part0Subpart1;
        Assert.assertEquals(execPart0Subpart1.getStepId(), "step-00");

        // // // // if
        ScenarioPartDeclaration part0Subpart2 = part0Subparts.get(2);
        ScenarioPartsTypeEnum part0Subpart2Type = part0Subpart2.getPartType();
        Assert.assertEquals(part0Subpart2Type, ScenarioPartsTypeEnum.IF_PART);
        IfPartDeclaration ifPart0Subpart2 = (IfPartDeclaration) part0Subpart2;
        Assert.assertEquals(ifPart0Subpart2.getLeft(), "left");
        Assert.assertEquals(ifPart0Subpart2.getOperator(), "operator");
        Assert.assertEquals(ifPart0Subpart2.getRight(), "right");
        Assert.assertEquals(ifPart0Subpart2.getDescription(), "some other description");
        List<ScenarioPartDeclaration> part0Subpart2Subparts = ifPart0Subpart2.getSubpartsList();
        Assert.assertEquals(part0Subpart2Subparts.size(), 1);

        // // // // // return
        ScenarioPartDeclaration part0Subpart2Subpart0 = part0Subpart2Subparts.get(0);
        ScenarioPartsTypeEnum part0Subpart2Subpart0Type = part0Subpart2Subpart0.getPartType();
        Assert.assertEquals(part0Subpart2Subpart0Type, ScenarioPartsTypeEnum.RETURN);
        ReturnPartDeclaration returnPart0Subpart2Subpart0 = (ReturnPartDeclaration) part0Subpart2Subpart0;
        Assert.assertEquals(returnPart0Subpart2Subpart0.getCheckpointId(), "checkpoint-00");
        Assert.assertEquals(part0Subpart2Subpart0.getSubpartsList().size(), 0);

        // // // else
        ScenarioPartDeclaration part1 = parts.get(1);
        ScenarioPartsTypeEnum part1Type = part1.getPartType();
        Assert.assertEquals(part1Type, ScenarioPartsTypeEnum.ELSE_PART);
        ElsePartDeclaration elsePart1 = (ElsePartDeclaration) part1;
        Assert.assertEquals(elsePart1.getLeft(), "left-value");
        Assert.assertEquals(elsePart1.getOperator(), "some-uoperator");
        Assert.assertEquals(elsePart1.getRight(), "right-value");
        Assert.assertEquals(elsePart1.getDescription(), "some description");
        List<ScenarioPartDeclaration> part1Subparts = part1.getSubpartsList();
        Assert.assertEquals(part1Subparts.size(), 2);

        // // // // scenario step exec
        ScenarioPartDeclaration part1Subpart0 = part1Subparts.get(0);
        ScenarioPartsTypeEnum part1Subpart0Type = part1Subpart0.getPartType();
        Assert.assertEquals(part1Subpart0Type, ScenarioPartsTypeEnum.DO_SCENARIO_STEP_PART);
        DoScenarioStepPartDeclaration execPart1Subpart0 = (DoScenarioStepPartDeclaration) part1Subpart0;
        Assert.assertEquals(execPart1Subpart0.getStepId(), "step-00");
        Assert.assertEquals(execPart1Subpart0.getSubpartsList().size(), 0);

        // // // // end
        ScenarioPartDeclaration part1Subpart1 = part1Subparts.get(1);
        ScenarioPartsTypeEnum part1Subpart1Type = part1Subpart1.getPartType();
        Assert.assertEquals(part1Subpart1Type, ScenarioPartsTypeEnum.END_PART);
        EndPartDeclaration endPart1Subpart1 = (EndPartDeclaration) part1Subpart1;
        Assert.assertEquals(endPart1Subpart1.getDescription(), "some end description");
        Assert.assertEquals(endPart1Subpart1.getSubpartsList().size(), 0);

        // // // else
        ScenarioPartDeclaration part2 = parts.get(2);
        ScenarioPartsTypeEnum part2Type = part2.getPartType();
        Assert.assertEquals(part2Type, ScenarioPartsTypeEnum.ELSE_PART);
        ElsePartDeclaration elsePart2 = (ElsePartDeclaration) part2;
        Assert.assertEquals(elsePart2.getLeft(), "left");
        Assert.assertEquals(elsePart2.getOperator(), "operator");
        Assert.assertEquals(elsePart2.getRight(), "some right");
        Assert.assertEquals(elsePart2.getDescription(), "ohoh");
        List<ScenarioPartDeclaration> part2Subparts = part2.getSubpartsList();
        Assert.assertEquals(part2Subparts.size(), 1);

        // // // // error
        ScenarioPartDeclaration part2Subpart0 = part2Subparts.get(0);
        ScenarioPartsTypeEnum part2Subpart0Type = part2Subpart0.getPartType();
        Assert.assertEquals(part2Subpart0Type, ScenarioPartsTypeEnum.ERROR_PART);
        ErrorPartDeclaration errorPart2Subpart0 = (ErrorPartDeclaration) part2Subpart0;
        Assert.assertEquals(errorPart2Subpart0.getDescription(), "some-error-part");
        Assert.assertEquals(part2Subpart0.getSubpartsList().size(), 0);

        // // // else
        ScenarioPartDeclaration part3 = parts.get(3);
        ScenarioPartsTypeEnum part3Type = part3.getPartType();
        Assert.assertEquals(part2Type, ScenarioPartsTypeEnum.ELSE_PART);
        ElsePartDeclaration elsePart3 = (ElsePartDeclaration) part3;
        Assert.assertEquals(elsePart3.getLeft(), "left-yeah");
        Assert.assertEquals(elsePart3.getOperator(), "operator-yeah");
        Assert.assertEquals(elsePart3.getRight(), "right-yeah");
        Assert.assertEquals(elsePart3.getDescription(), "description yeah");
        List<ScenarioPartDeclaration> part3Subparts = part3.getSubpartsList();
        Assert.assertEquals(part3Subparts.size(), 1);

        // // // // not computed
        ScenarioPartDeclaration part3Subpart0 = part3Subparts.get(0);
        ScenarioPartsTypeEnum part3Subpart0Type = part3Subpart0.getPartType();
        Assert.assertEquals(part3Subpart0Type, ScenarioPartsTypeEnum.NOT_COMPUTED);
        NotComputedPartDeclaration notPart3Subpart0 = (NotComputedPartDeclaration) part3Subpart0;
        Assert.assertEquals(notPart3Subpart0.getDescription(), "description of why not computed");
        Assert.assertEquals(part3Subpart0.getSubpartsList().size(), 0);

    }

    @Test(expectedExceptions = TestSuiteFileException.class)
    public void testNotProperXML_EmptyTestSuite() throws FileNotFoundException, IOException, TestSuiteFileException {
        XMLDeclarationReader reader = new XMLDeclarationReader("tests-res/com/szeldon/declatest"
                + "/declaration/not_proper-declaration-01.xml");
        reader.addSettingsReaderPlugin(new JMSSettingsReaderPlugin());
        reader.readTestsSuiteDeclaration();
    }

    @Test(expectedExceptions = TestSuiteFileException.class)
    public void testNotProperXML_BadAfterError() throws FileNotFoundException, IOException, TestSuiteFileException {
        XMLDeclarationReader reader = new XMLDeclarationReader("tests-res/com/szeldon/declatest"
                + "/declaration/not_proper-declaration-02.xml");
        reader.addSettingsReaderPlugin(new JMSSettingsReaderPlugin());
        TestsSuiteDeclaration suite = reader.readTestsSuiteDeclaration();
    }

    @Test(expectedExceptions = TestSuiteFileException.class)
    public void testNotProperXML_BadAfterReturn() throws FileNotFoundException, IOException, TestSuiteFileException {
        XMLDeclarationReader reader = new XMLDeclarationReader("tests-res/com/szeldon/declatest"
                + "/declaration/not_proper-declaration-03.xml");
        reader.addSettingsReaderPlugin(new JMSSettingsReaderPlugin());
        TestsSuiteDeclaration suite = reader.readTestsSuiteDeclaration();
    }

    @Test(expectedExceptions = TestSuiteFileException.class)
    public void testNotProperXML_BadAfterEnd() throws FileNotFoundException, IOException, TestSuiteFileException {
        XMLDeclarationReader reader = new XMLDeclarationReader("tests-res/com/szeldon/declatest"
                + "/declaration/not_proper-declaration-04.xml");
        reader.addSettingsReaderPlugin(new JMSSettingsReaderPlugin());
        TestsSuiteDeclaration suite = reader.readTestsSuiteDeclaration();
    }

    @Test(expectedExceptions = TestSuiteFileException.class)
    public void testNotProperXML_DuplicateIds() throws FileNotFoundException, IOException, TestSuiteFileException {
        XMLDeclarationReader reader = new XMLDeclarationReader("tests-res/com/szeldon/declatest"
                + "/declaration/not_proper-declaration-05.xml");
        reader.addSettingsReaderPlugin(new JMSSettingsReaderPlugin());
        TestsSuiteDeclaration suite = reader.readTestsSuiteDeclaration();
    }

    @Test(expectedExceptions = TestSuiteFileException.class, expectedExceptionsMessageRegExp = ".*endpoint-01.*step-01.*")
    public void testNotProperXML_MissingIds() throws FileNotFoundException, IOException, TestSuiteFileException {
        XMLDeclarationReader reader = new XMLDeclarationReader("tests-res/com/szeldon/declatest"
                + "/declaration/not_proper-declaration-06.xml");
        reader.addSettingsReaderPlugin(new JMSSettingsReaderPlugin());
        TestsSuiteDeclaration suite = reader.readTestsSuiteDeclaration();
    }

    @Test(expectedExceptions = TestSuiteFileException.class, expectedExceptionsMessageRegExp = ".*checkpoint-02.*")
    public void testNotProperXML_MissingIds2() throws FileNotFoundException, IOException, TestSuiteFileException {
        XMLDeclarationReader reader = new XMLDeclarationReader("tests-res/com/szeldon/declatest"
                + "/declaration/not_proper-declaration-07.xml");
        reader.addSettingsReaderPlugin(new JMSSettingsReaderPlugin());
        TestsSuiteDeclaration suite = reader.readTestsSuiteDeclaration();
    }

    @Test()
    public void testNotProperXML_MissingIds3() throws FileNotFoundException, IOException, TestSuiteFileException {
        // TODO add test for checking a case when Return part has checkpointId of a Checkpoint that isn't in the same
        // part of the tree
    }
}
